home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume7 / hostup < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  8.9 KB

  1. Subject:  v07i037:  An alternative to the BSD ruptime command
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: alasdair@ux.cs.man.ac.uk
  6. Mod.sources: Volume 7, Issue 37
  7. Archive-name: hostup
  8.  
  9. [  This program can be very expensive to run.  -r$  ]
  10.  
  11. Inspired by the Tektronix TCP/IP 'hostup' command, I've done an
  12. equivalent thing for 4.[23] UNIX.  Tried and tested on a 4.3 Beta
  13. Vax8600, and SUN3 version 3.0.  It's primitive stuff, so feel free to
  14. enhance it to suit your own needs!
  15. Alasdair
  16. #! /bin/sh
  17. # This is a shell archive, meaning:
  18. # 1. Remove everything above the #! /bin/sh line.
  19. # 2. Save the resulting text in a file.
  20. # 3. Execute the file with /bin/sh (not csh) to create the files:
  21. #    hostup.1
  22. #    Makefile
  23. #    hostup.c
  24. #    hostup.h
  25. #    hostupd.c
  26. # This archive created: Sat Sep  6 16:01:51 1986
  27. export PATH; PATH=/bin:$PATH
  28. echo shar: extracting "'hostup.1'" '(1386 characters)'
  29. if test -f 'hostup.1'
  30. then
  31.     echo shar: will not over-write existing file "'hostup.1'"
  32. else
  33. cat << \SHAR_EOF > 'hostup.1'
  34. .TH HOSTUP l "6 September 1986"
  35. .SH NAME
  36. hostup, hostupd \- network status report
  37. .SH SYNOPSIS
  38. .B hostup
  39. .SH DESCRIPTION
  40. .I hostup
  41. prints a list of network node names, with an indication of their
  42. reachability.  It relies on a copy of
  43. .I hostupd
  44. running:
  45. .I hostupd
  46. polls machines in the /etc/hosts file and maintains
  47. a binary file of its results.
  48. .PP
  49. .I hostupd
  50. polls each machine by attempting to
  51. .IR connect (2)
  52. to an unused TCP port, and logging the type of error returned.  This
  53. mechanism is a useful alternative to
  54. .IR ruptime (1),
  55. as it works with non-BSD machines, as well as with machines not
  56. running the ruptime daemon (such as diskless
  57. .B SUN
  58. workstations).
  59. .SH "SEE ALSO"
  60. ruptime(1)
  61. .br
  62. connect(2)
  63. .SH BUGS
  64. The polling process is
  65. .B slow
  66. (taking perhaps 75 minutes to complete one poll of the internal
  67. network at Manchester at weekends, when most machines are switched off)
  68. as it depends upon the
  69. .IR connect (2)
  70. timeout for each machine that is down.
  71. .PP
  72. .I hostupd
  73. currently sleeps for 5 minutes every time round the loop of machines:
  74. this is not strictly necessary if enough machines are down!
  75. .PP
  76. For machines connected to the Internet, polling every machine in
  77. /etc/hosts is probably a mistake.
  78. .PP
  79. The order of polling and the format of displaying the hosts is
  80. optimised for my network and my convenience.
  81. .SH AUTHOR
  82. Alasdair Rawsthorne (arawsthorne@uk.ac.man.cs.ux).
  83.  
  84. SHAR_EOF
  85. if test 1386 -ne "`wc -c < 'hostup.1'`"
  86. then
  87.     echo shar: error transmitting "'hostup.1'" '(should have been 1386 characters)'
  88. fi
  89. fi # end of overwriting check
  90. echo shar: extracting "'Makefile'" '(119 characters)'
  91. if test -f 'Makefile'
  92. then
  93.     echo shar: will not over-write existing file "'Makefile'"
  94. else
  95. cat << \SHAR_EOF > 'Makefile'
  96. hostup:    hostup.c hostup.h
  97.     cc -O -o hostup hostup.c -ltermcap
  98.  
  99. hostupd:    hostupd.c hostup.h
  100.     cc -O -o hostupd hostupd.c
  101. SHAR_EOF
  102. if test 119 -ne "`wc -c < 'Makefile'`"
  103. then
  104.     echo shar: error transmitting "'Makefile'" '(should have been 119 characters)'
  105. fi
  106. fi # end of overwriting check
  107. echo shar: extracting "'hostup.c'" '(2480 characters)'
  108. if test -f 'hostup.c'
  109. then
  110.     echo shar: will not over-write existing file "'hostup.c'"
  111. else
  112. cat << \SHAR_EOF > 'hostup.c'
  113. #include <stdio.h>
  114.  
  115. #include <errno.h>
  116. #include <sys/types.h>
  117. #include <sys/socket.h>
  118. #include <netinet/in.h>
  119. #include <sys/time.h>
  120.  
  121. #include "hostup.h"
  122.  
  123. #define FIELDWIDTH 11
  124.  
  125. FILE *f;            /* input file */
  126. struct timeval  first, last;    /* GMT of polls */
  127. struct timezone timezone;    /* my offset */
  128. char * timeof();
  129. int currentpos = 0, width = 80;    /* for formatting screen */
  130. char tbuf[1024];
  131.  
  132. u_long lastnetwork = 0;
  133.  
  134. struct perhost thishost;
  135.  
  136. main()
  137. {
  138.   long seconds;
  139.   int cols;
  140.   u_long network;
  141.   if (tgetent(tbuf, getenv("TERM")) == 1) {
  142.     if ((cols = tgetnum("co")) > 0) {
  143.       width = cols;
  144.     }
  145.   }
  146.   if ((f = fopen(FILENAME, "r")) == NULL) {
  147.     perror(FILENAME);
  148.     exit(1);
  149.   }
  150.   gettimeofday(&first, &timezone);
  151.   last.tv_sec = 0;
  152.   while (fread(&thishost, sizeof(thishost), 1, f) == 1) {
  153.     network = ntohl(thishost.ph_to.sin_addr.s_addr);
  154.     if (IN_CLASSA(network)) {
  155.       network &= IN_CLASSA_NET;
  156.     } else if (IN_CLASSB(network)) {
  157.       network &= IN_CLASSB_NET;
  158.     } else {
  159.       network &= IN_CLASSC_NET;
  160.     }
  161.     if (network != lastnetwork) {
  162.       lastnetwork = network;
  163.       donl();
  164.     }
  165.     printstat(thishost.ph_name, thishost.ph_result);
  166.     seconds = thishost.ph_time.tv_sec;
  167.     if (first.tv_sec > seconds) {
  168.       first.tv_sec = seconds;
  169.     }
  170.     if (last.tv_sec < seconds) {
  171.       last.tv_sec = seconds;
  172.     }
  173.   }
  174.   donl();
  175.   printf("Polled from %s", timeof(&first));
  176.   printf(" to %s; KEY: ", timeof(&last));
  177.   printstat("Up", ECONNREFUSED);
  178.   printstat("Down", ETIMEDOUT);
  179.   printstat("UnReachable", ENETUNREACH);
  180.   donl();
  181.   exit(0);
  182. }
  183.  
  184. char *
  185. timeof(tp)
  186.      struct timeval *tp;
  187. {
  188.   char *rp;
  189.   struct tm *tm;
  190.   tm = localtime(&tp->tv_sec);
  191.   rp = asctime(tm);
  192.   rp[19] = '\0';        /* truncate before timezone */
  193.   return(rp + 11);        /* return just the time */
  194. }
  195.  
  196. printstat(name, errno)
  197.      char *name;
  198. {
  199.   int up = 0;
  200.   char extra = ' ';
  201.   switch(errno) {
  202.   case ECONNREFUSED:
  203.     up = 1;
  204.     break;
  205.   case 0:
  206.     up = 1;
  207.     extra = '!';
  208.     break;
  209.   case ETIMEDOUT:
  210.     break;
  211.   case ENETUNREACH:
  212.     extra = '-';
  213.     break;
  214.   default:
  215.     extra = '?';
  216.     break;
  217.   }
  218.   if (up) {
  219.     printf(" %s%c ", name, extra);
  220.   } else {
  221.     printf("(%s)%c", name, extra);
  222.   }
  223.   if (currentpos > (width - (2 * FIELDWIDTH))) {
  224.     donl();
  225.   } else {
  226.     int i;
  227.     currentpos += FIELDWIDTH;
  228.     for (i = strlen(name)+3; i < FIELDWIDTH; i++) {
  229.       putchar(' ');
  230.     }
  231.   }
  232. }
  233.  
  234. donl()
  235. {
  236.   if (currentpos) {
  237.     putchar('\n');
  238.   }
  239.   currentpos = 0;
  240. }
  241. SHAR_EOF
  242. if test 2480 -ne "`wc -c < 'hostup.c'`"
  243. then
  244.     echo shar: error transmitting "'hostup.c'" '(should have been 2480 characters)'
  245. fi
  246. fi # end of overwriting check
  247. echo shar: extracting "'hostup.h'" '(186 characters)'
  248. if test -f 'hostup.h'
  249. then
  250.     echo shar: will not over-write existing file "'hostup.h'"
  251. else
  252. cat << \SHAR_EOF > 'hostup.h'
  253. #define MAXHOSTCHARS 12
  254. #define FILENAME "/usr/adm/host up"
  255.  
  256. struct perhost {
  257.   char            ph_name[MAXHOSTCHARS];
  258.   struct sockaddr_in    ph_to;
  259.   struct timeval    ph_time;
  260.   int            ph_result;
  261. };
  262. SHAR_EOF
  263. if test 186 -ne "`wc -c < 'hostup.h'`"
  264. then
  265.     echo shar: error transmitting "'hostup.h'" '(should have been 186 characters)'
  266. fi
  267. fi # end of overwriting check
  268. echo shar: extracting "'hostupd.c'" '(2349 characters)'
  269. if test -f 'hostupd.c'
  270. then
  271.     echo shar: will not over-write existing file "'hostupd.c'"
  272. else
  273. cat << \SHAR_EOF > 'hostupd.c'
  274. #include <stdio.h>
  275.  
  276. #include <sys/types.h>
  277. #include <sys/ioctl.h>
  278. #include <sys/socket.h>
  279. #include <sys/time.h>
  280. #include <netinet/in.h>
  281.  
  282. #include <netdb.h>
  283.  
  284. #define HISPORT 919        /* 'cos that's what tektronix use */
  285. #define MAXHOSTS 200
  286. #define SLEEPTIME 300        /* 5 mins wait at end of loop */
  287.  
  288. #include "hostup.h"
  289.  
  290. extern int errno;
  291.  
  292. struct hostent *gethostent(), *host;
  293. int inetcomp();
  294. int s;                /* socket number */
  295. FILE *f;            /* output file */
  296. struct timezone timezone;    /* somewhere to ignore it */
  297.  
  298. struct perhost thishost[MAXHOSTS];
  299. int nohosts = 0;
  300.  
  301. main()
  302. {
  303.   if ((f = fopen(FILENAME, "w")) == NULL) {
  304.     perror(FILENAME);
  305.     exit(1);
  306.   }
  307.   readhosts();            /* find a table of hosts to poll */
  308. #ifndef DEBUG
  309.   if (fork())
  310.     exit(0);
  311.   { int s;
  312.     for (s = 0; s < 10; s++)
  313.       if (s != fileno(f))
  314.     (void) close(s);
  315.     (void) open("/", 0);
  316.     (void) dup2(0, 1);
  317.     (void) dup2(0, 2);
  318.     s = open("/dev/tty", 2);
  319.     if (s >= 0) {
  320.       ioctl(s, TIOCNOTTY, 0);
  321.       (void) close(s);
  322.     }
  323.   }
  324. #endif
  325.   while(1) {
  326.     fseek(f, 0L, 0);        /* keep writing from start */
  327.     pollhosts();
  328.     sleep(SLEEPTIME);
  329.   }
  330. }
  331.  
  332. readhosts()
  333. {
  334.   while ((host = gethostent()) != NULL) {
  335.     strncpy(thishost[nohosts].ph_name, host->h_name, MAXHOSTCHARS);
  336.     thishost[nohosts].ph_name[MAXHOSTCHARS-1] = '\0';
  337.     bzero((char *)&thishost[nohosts].ph_to, sizeof(thishost[nohosts].ph_to));
  338.     bcopy(host->h_addr, (char *)&thishost[nohosts].ph_to.sin_addr, host->h_length);
  339.     thishost[nohosts].ph_to.sin_family = host->h_addrtype;
  340.     thishost[nohosts].ph_to.sin_port = HISPORT;
  341.     nohosts++;
  342.     if (nohosts == MAXHOSTS)
  343.       break;
  344.   }
  345.   endhostent();
  346.   qsort(thishost, nohosts, sizeof(thishost[0]), inetcomp);
  347. }
  348.  
  349. inetcomp(a, b)
  350.      struct perhost *a, *b;
  351. {
  352.   return(ntohl(a->ph_to.sin_addr.s_addr) - ntohl(b->ph_to.sin_addr.s_addr));
  353. }
  354.  
  355. pollhosts()
  356. {
  357.   int i;
  358.   for (i = 0; i < nohosts; i++) {
  359.     s = socket(AF_INET, SOCK_STREAM, 0);
  360.     if (s < 0) {
  361. #ifdef DEBUG
  362.       perror("socket:");
  363. #endif      
  364.       exit(1);
  365.     }
  366.     if (connect(s, (char *)&thishost[i].ph_to,
  367.         sizeof(thishost[i].ph_to)) < 0) {
  368.       thishost[i].ph_result = errno;
  369.     } else {
  370.       thishost[i].ph_result = 0;
  371.     }
  372.     gettimeofday(&thishost[i].ph_time, &timezone);
  373.     fwrite(&thishost[i], sizeof(thishost[i]), 1, f);
  374.     fflush(f);
  375.     (void) close(s);            /* ! */
  376.   }
  377. }
  378. SHAR_EOF
  379. if test 2349 -ne "`wc -c < 'hostupd.c'`"
  380. then
  381.     echo shar: error transmitting "'hostupd.c'" '(should have been 2349 characters)'
  382. fi
  383. fi # end of overwriting check
  384. #    End of shell archive
  385. exit 0
  386.